﻿using Microsoft.Playwright;

namespace Region.Spider
{
    public class AreaSpider : IAsyncDisposable
    {
        public Queue<string> TownQueue = new Queue<string>();
        public SemaphoreSlim Slim = new SemaphoreSlim(3);

        public IPlaywright Playwright;
        public IBrowser Browser;

        private async Task StartIfNotAsync()
        {
            Console.WriteLine("开始爬虫初始化..");
            if (this.Browser == null)
            {
                this.Playwright = await Microsoft.Playwright.Playwright.CreateAsync();
                this.Browser = await this.Playwright.Webkit.LaunchAsync();
            }
            Console.WriteLine("爬虫初始化完成..");
        }

        public async Task<(IList<AreaItem>, IList<TownAreaItem>)> DoAsync()
        {
            await this.StartIfNotAsync();
            var year = DateTime.Now.Year - 1;
            var baseUrl = $"https://www.stats.gov.cn/sj/tjbz/tjyqhdmhcxhfdm/{year}";
            var page = await this.Browser.NewPageAsync();

            var root_url = $"{baseUrl}/index.html";
            Console.WriteLine($"开始执行采集:{root_url}");
            await page.GotoAsync(root_url);
            var areaItems = new List<AreaItem>();
            var tasks = new List<Task<TownAreaItem>>();
            //采集省
            foreach (var prov_a in await page.Locator("tr.provincetr a").AllAsync())
            {
                var prov_code = await prov_a.GetAreaCodeFromHrefAsync(2);
                var prov_name = await prov_a.GetAreaNameAsync();
                //var url = await prov_a.GetAttributeAsync("href");

                var provItem = new AreaItem(prov_code, prov_name, new List<AreaItem>());
                await prov_a.ClickAsync();
                var prov_url = page.Url;//当前省URL
                //采集市
                foreach (var city_tr in await page.Locator("tr.citytr").AllAsync())
                {
                    var city_as = await city_tr.Locator("a").AllAsync();
                    var city_code = await city_as[0].GetAreaCodeAsync(4);
                    var city_name = await city_as[1].GetAreaNameAsync();
                    //Console.WriteLine($"--{cid},{cname}");
                    var cityItem = new AreaItem(city_code, city_name, new List<AreaItem>());
                    await city_as[0].ClickAsync();
                    var city_url = page.Url;//当前市URL
                    //采集区
                    foreach (var county_tr in await page.Locator("tr.countytr,tr.towntr").AllAsync())
                    {
                        var county_tds = await county_tr.Locator("td").AllAsync();
                        var county_code = await county_tds[0].GetAreaCodeAsync(6);
                        var county_name = await county_tds[1].GetAreaNameAsync();

                        var countyItem = new AreaItem(county_code, county_name, null);
                        var county_as = await county_tr.Locator("a").AllAsync();
                        if (county_as.Count > 0)
                        {
                            //await county_as[0].ClickAsync();
                            var county_url = await county_as[0].GetAttributeAsync("href");
                            county_url = $"{baseUrl}/{prov_code}/{county_url}";
                            //Console.WriteLine($"----{county_name}{county_code} 开始采集..");

                            //var townTask = Task.Run(() => GetTownsAsync(city_code, county_name, county_url));
                            //tasks.Add(townTask);
                        }
                        cityItem.Children.Add(countyItem);
                        //Console.WriteLine($"----{aid},{aname}");
                        //await page.GotoAsync(city_url);
                    }
                    provItem.Children.Add(cityItem);
                    Console.WriteLine($"--{city_name}{city_code} 采集完成..");
                    await page.GotoAsync(prov_url);
                }
                areaItems.Add(provItem);
                //Console.WriteLine($"{pname}结束采集");
                Console.WriteLine($"{prov_name}{prov_code} 采集完成..");
                await page.GotoAsync(root_url);
            }
            Task.WaitAll(tasks.ToArray());
            var townItems = tasks.Select(t=>t.Result).ToList();
            Console.WriteLine("数据采集完成..");
            return (areaItems, townItems);
        }

        public async Task<TownAreaItem> GetTownsAsync(string countyCode, string countyName, string url)
        {
            await this.Slim.WaitAsync(100000);
            //Console.WriteLine($"开始处理:{url}..");
            
            var result = new TownAreaItem(countyCode, new List<AreaItem>());
            var page = await this.Browser.NewPageAsync();
            try
            {
                await page.GotoAsync(url);

                foreach (var town_tr in await page.Locator("tr.towntr").AllAsync())
                {
                    var town_tds = await town_tr.Locator("td").AllAsync();
                    var town_code = await town_tds[0].GetAreaCodeAsync(8);
                    var town_name = await town_tds[1].GetAreaNameAsync();
                    //Console.WriteLine($"--{cid},{cname}");
                    var townItem = new AreaItem(town_code, town_name, null);
                    result.Towns.Add(townItem);
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"{countyCode},{url}:{ex}");
            }
            finally
            {
                Console.WriteLine($"----{countyName}{countyCode} 采集完成..");
                this.Slim.Release();
                await page.CloseAsync();
            }
            return result;
        }

        public async ValueTask DisposeAsync()
        {
            await this.Browser.DisposeAsync();
            this.Playwright.Dispose();
        }
    }
}
